package main

import (
	"bytes"
	"fmt"
	"gitee.com/iotas/iota-cli/toolkit"
	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
	"gopkg.in/yaml.v3"
	"io/fs"
	"io/ioutil"
	"os"
	ose "os/exec"
	"path"
	"path/filepath"
	"strings"

	"gitee.com/iotas/iota-cli/skeleton"
	format "gitee.com/iotas/toolkit/proto_format"
	proto "gitee.com/iotas/toolkit/proto_parser"
)

func main() {
	exec()
}

func exec() {
	if NeedUpdateFlag {
		fmt.Println("稍等, 正在执行更新操作...")
		if err := updateBuilder().Execute(); err != nil {
			_, _ = fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}

		if len(os.Args) >= 2 && os.Args[1] == "update" {
			return // 是更新操作 自己取消掉 前面已经做了
		}
	}
	if err := rootCmd.Execute(); err != nil {
		_, _ = fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

func init() {
	if checkCliVersion() {
		NeedUpdateFlag = true
	}
	rootCmd.AddCommand(versionInfo())                    // 打印iota-cli版本信息
	rootCmd.AddCommand(addRPCCommand())                  // 新增一个RPC
	rootCmd.AddCommand(addAPICommand())                  // 新增一个API
	rootCmd.AddCommand(updateBuilder())                  // 检测并更新iota-cli
	rootCmd.AddCommand(addSvcCommand())                  // 添加一个服务
	rootCmd.AddCommand(addRouteCommand())                // 添加一个路由组
	rootCmd.AddCommand(buildRunCommand())                // 快速运行omega项目
	rootCmd.AddCommand(outputMdCommand())                // 生成一个api的md文档
	rootCmd.AddCommand(buildHTTPCommand())               // 生成一个新项目
	rootCmd.AddCommand(buildProtoCommand())              // proto生成
	rootCmd.AddCommand(formatProtoCommand())             // 格式化一个proto文件
	rootCmd.AddCommand(installDependentPackageCommand()) // 更新iota-cli依赖的工具链
}

var (
	rootCmd = &cobra.Command{
		Use:   "iota-cli",
		Short: "iota-cli 是基于 iota 库的一个提高生产效率的工具链",
	}
)

func installDependentPackageCommand() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "dep",
		Short: "更新iota-cli依赖的工具链",
		Run: func(cmd *cobra.Command, args []string) {
			// 是否已经安装 protoc
			installProtoc()

			// 更新 protoc-go-inject-tag
			installProtocGoInjectTag()

			// 更新 protoc-gen-go
			installProtocGenGo()

			// 更新 grpc
			installProtocGenGoGrpc()

			// iota-cli 自我更新
			_ = upgradeBuilder()
		},
	}

	return cmd
}

func versionInfo() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "version",
		Short: "打印iota-cli版本信息",
		Run: func(cmd *cobra.Command, args []string) {
			// 检测环境
			var homeDir string
			if toolkit.GetGOOS() == toolkit.Windows {
				homeDir = os.Getenv("USERPROFILE")
				if homeDir == "" {
					driveName := os.Getenv("HOMEDRIVE")
					homePath := os.Getenv("HOMEPATH")
					homeDir = fmt.Sprintf("%s%s\\", driveName, homePath)
				} else {
					homeDir = fmt.Sprintf("%s\\", homeDir)
				}
			} else {
				homeDir = os.Getenv("HOME")
				if homeDir == "" {
					userData, err := ose.Command("sh", "-c", "eval echo $USER").CombinedOutput()
					if err != nil {
						_, _ = fmt.Fprintf(os.Stderr, "get user info err: %+v\n", err)
						return
					}
					userName := strings.ReplaceAll(string(userData), "\n", "")
					if userName == "" {
						return
					}
					if userName == "root" {
						homeDir = fmt.Sprintf("/root/")
					} else {
						homeDir = fmt.Sprintf("/home/%s/", userName)
					}
				} else {
					homeDir = fmt.Sprintf("%s/", homeDir)
				}
			}
			configFile := fmt.Sprintf("%s%s", homeDir, builderConfig)
			var config = BuilderConfig{}

			_, err := os.Stat(configFile)
			if err != nil {
				if !os.IsNotExist(err) {
					_, _ = fmt.Fprintf(os.Stderr, "check iota-cli config err: %+v\n", err)
					return
				}
				// 新建配置文件
				data, err := yaml.Marshal(config)
				if err != nil {
					_, _ = fmt.Fprintf(os.Stderr, "marshal config file err: %+v\n", err)
					return
				}
				if err := ioutil.WriteFile(configFile, data, fs.ModePerm); err != nil {
					_, _ = fmt.Fprintf(os.Stderr, "write new iota-cli config err: %+v\n", err)
					return
				}
			}
			content, err := ioutil.ReadFile(configFile)
			if err != nil {
				_, _ = fmt.Fprintf(os.Stderr, "open iota-cli config err: %+v\n", err)
				return
			}

			if err := yaml.Unmarshal(content, &config); err != nil {
				_, _ = fmt.Fprintf(os.Stderr, "unmarshal iota-cli config err: %+v\n", err)
				return
			}

			_, _ = fmt.Fprintf(os.Stdout, ProjectName+"\n-----\n更新时间: %+v\nCommitID: %+v\n更新说明: %+v\n-----\n",
				config.UpdatedAt, config.Commit, config.Message)
		},
	}

	return cmd
}

func updateBuilder() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "update",
		Short: "检测并更新iota-cli",
		Run: func(cmd *cobra.Command, args []string) {
			// iota-cli 自我更新
			if err := upgradeBuilder(); err != nil {
				return
			}
			// 检测环境
			var homeDir string
			if toolkit.GetGOOS() == toolkit.Windows {
				homeDir = os.Getenv("USERPROFILE")
				if homeDir == "" {
					driveName := os.Getenv("HOMEDRIVE")
					homePath := os.Getenv("HOMEPATH")
					homeDir = fmt.Sprintf("%s%s\\", driveName, homePath)
				} else {
					homeDir = fmt.Sprintf("%s\\", homeDir)
				}
			} else {
				homeDir = os.Getenv("HOME")
				if homeDir == "" {
					userData, err := ose.Command("sh", "-c", "eval echo $USER").CombinedOutput()
					if err != nil {
						_, _ = fmt.Fprintf(os.Stderr, "get user info err: %+v\n", err)
						return
					}
					userName := strings.ReplaceAll(string(userData), "\n", "")
					if userName == "" {
						return
					}
					if userName == "root" {
						homeDir = fmt.Sprintf("/root/")
					} else {
						homeDir = fmt.Sprintf("/home/%s/", userName)
					}
				} else {
					homeDir = fmt.Sprintf("%s/", homeDir)
				}
			}
			configFile := fmt.Sprintf("%s%s", homeDir, builderConfig)
			var config = BuilderConfig{}

			_, err := os.Stat(configFile)
			if err != nil {
				if !os.IsNotExist(err) {
					_, _ = fmt.Fprintf(os.Stderr, "check iota-cli config err: %+v\n", err)
					return
				}
				// 新建配置文件
				data, err := yaml.Marshal(config)
				if err != nil {
					_, _ = fmt.Fprintf(os.Stderr, "marshal config file err: %+v\n", err)
					return
				}
				if err := ioutil.WriteFile(configFile, data, fs.ModePerm); err != nil {
					_, _ = fmt.Fprintf(os.Stderr, "write new iota-cli config err: %+v\n", err)
					return
				}
			}
			content, err := ioutil.ReadFile(configFile)
			if err != nil {
				_, _ = fmt.Fprintf(os.Stderr, "open iota-cli config err: %+v\n", err)
				return
			}

			if err := yaml.Unmarshal(content, &config); err != nil {
				_, _ = fmt.Fprintf(os.Stderr, "unmarshal iota-cli config err: %+v\n", err)
				return
			}

			// 写入配置
			commit, err := toolkit.GetRepoLatestCommit()
			if err != nil {
				_, _ = fmt.Fprintf(os.Stderr, "get repo commit info err: %+v\n", err)
				return
			}
			ca, _ := toolkit.RFC3339ToTime(commit.Commit.Committer.Date)
			config.UpdatedAt = ca.Format("2006-01-02 15:04:05")
			config.UpdatedAtUnix = ca.Unix()
			config.Commit = commit.Sha[:8]
			config.Message = toolkit.Trim(commit.Commit.Message)
			config.CheckedAtUnix = ca.Unix()

			newBody, err := yaml.Marshal(config)
			if err != nil {
				_, _ = fmt.Fprintf(os.Stderr, "marshal iota-cli config err: %+v\n", err)
				return
			}

			if err := ioutil.WriteFile(configFile, newBody, fs.ModePerm); err != nil {
				_, _ = fmt.Fprintf(os.Stderr, "rewrite iota-cli config err: %+v\n", err)
				return
			}
		},
		DisableFlagParsing: true,
	}

	return cmd
}

func buildHTTPCommand() *cobra.Command {
	var name string
	output, _ := os.Getwd()
	cmd := &cobra.Command{
		Use:   "create",
		Short: "创建一个新项目",
		Run: func(cmd *cobra.Command, args []string) {
			b := &skeleton.Builder{
				Path: output,
				Name: name,
			}
			b.Path = path.Join(output, b.Name)
			if err := b.Build(); err != nil {
				_, _ = fmt.Fprint(os.Stderr, err)
				os.Exit(1)
			}
		},
	}
	cmd.Flags().StringVar(&name, "name", "demo", "项目名称")
	cmd.Flags().StringVar(&output, "path", output, "项目输出路径")
	return cmd
}

func buildRunCommand() *cobra.Command {
	const (
		envLocal   = "local" // 本地环境
		envDev     = "dev"   // 开发环境
		envTest    = "test"  // 测试环境
		envRelease = "prod"  // 正式环境

		envLocalConfig   = "config_local.yaml"
		envDevConfig     = "config_dev.yaml"
		envTestConfig    = "config_test.yaml"
		envReleaseConfig = "config_prod.yaml"
	)
	var env = envLocal
	var envConfig = envLocalConfig
	var config = ""
	mainPath, _ := os.Getwd()
	cmd := &cobra.Command{
		Use:   "run",
		Short: "快速运行项目",
		Long:  "通过指定 env,path,config 等参数快速运行一个已有项目",
		Run: func(cmd *cobra.Command, args []string) {
			if len(args) == 0 {
				logrus.Errorf("run arg empty")
				return
			}

			if env == "" {
				env = os.Getenv("OMEGA_ENV")
			}
			if env == "" {
				env = envLocal
			}
			if env != "" {
				switch env {
				case envLocal:
					envConfig = envLocalConfig
				case envDev:
					envConfig = envDevConfig
				case envTest:
					envConfig = envTestConfig
				case envRelease:
					envConfig = envReleaseConfig
				}
			}

			if config != "" {
				envConfig = config
			}

			var params = []string{"run", mainPath, args[0], "--config", envConfig}

			var protocStdout bytes.Buffer
			var protocStderr bytes.Buffer
			protocCmd := ose.Command("go", params...)
			protocCmd.Stdout = &protocStdout
			protocCmd.Stderr = &protocStderr
			logrus.Infof("run: %s", protocCmd.String())
			if err := protocCmd.Run(); err != nil {
				logrus.Errorf("run err: %+v", err)
				logrus.Errorf("std_out: %s", protocStdout.String())
				logrus.Errorf("std_err: %s", protocStderr.String())
				return
			}
		},
	}
	cmd.Flags().StringVar(&env, "env", "", "指定运行环境, 如果没有指定该参数并且系统中没有指定 `OMEGA_ENV` 环境变量, 将默认指定 `local`")
	cmd.Flags().StringVar(&mainPath, "path", mainPath, "项目 main 函数入口路径")
	cmd.Flags().StringVar(&config, "config", "", "强制指定项目配置文件,不建议使用,这将覆盖env参数")
	return cmd
}

func buildProtoCommand() *cobra.Command {
	pbPath, _ := os.Getwd()
	var goOut = filepath.Dir(pbPath)
	var grpcOut = ""
	var include = []string{"."}
	var needFmt bool
	var noScope bool
	var dbType = "mdbc"

	// 解析项目下的iota-cli配置
	var parseConfig = func() Config {
		var c Config
		body, err := ioutil.ReadFile(builderConfig)
		if err != nil {
			return c
		}
		if err = yaml.Unmarshal(body, &c); err != nil {
			return c
		}
		return c
	}

	cmd := &cobra.Command{
		Use:   "gen",
		Short: "解析proto文件, 自动生成开发代码.",
		Long:  "生成代码时请在项目根目录下执行,默认生成路径为当前目录,所以proto依赖请写项目全路径\n命令说明: http://doc.heywoods.cn/web/#/47?page_id=385",
		Run: func(cmd *cobra.Command, args []string) {
			// 解析项目下的配置项
			c := parseConfig()
			err := proto.CodeGen(&proto.CodeGenConfig{
				PbFilePath:       pbPath,
				OutputPath:       goOut,
				GrpcOutputPath:   grpcOut,
				IncludePbFiles:   include,
				OutputNeedFormat: needFmt,
				NoGetScopeFunc:   noScope,
				DbDriveType:      dbType,
				FreqOutput:       c.FreqTo,
			})
			if err != nil {
				_, _ = fmt.Fprint(os.Stderr, err)
				os.Exit(1)
			}
		},
	}
	cmd.Flags().StringVar(&pbPath, "path", pbPath, "proto文件地址,支持传入目录")
	cmd.Flags().StringVar(&goOut, "out", goOut, "proto文件生成位置,是--go_out的别名")
	cmd.Flags().StringVar(&grpcOut, "grpc", grpcOut, "生成grpc,指定grpc生成位置,是--go-grpc_out的别名, 默认不生成")
	cmd.Flags().StringSliceVar(&include, "include", include, "proto文件依赖路径,是-I(-IPATH/--proto_path)的别名")
	cmd.Flags().BoolVar(&needFmt, "fmt", needFmt, "是否需要格式化输出的文件,开启时只需要指定 --fmt 后面不需要任何参数(可以确保代码风格统一)")
	cmd.Flags().BoolVar(&noScope, "no-scope", noScope, "是否忽略数据库驱动的GetScope()代码生成, 不建议开启")
	cmd.Flags().StringVar(&dbType, "db", dbType, "生成代码的数据库驱动类型,可选[mdbc,gdbc]")
	return cmd
}

func formatProtoCommand() *cobra.Command {
	pbPath, _ := os.Getwd()
	cmd := &cobra.Command{
		Use:   "fmt",
		Short: "格式化 proto 文件使其看的赏心悦目",
		Run: func(cmd *cobra.Command, args []string) {
			err := format.Format(pbPath)
			if err != nil {
				_, _ = fmt.Fprint(os.Stderr, err)
				os.Exit(1)
			}
		},
	}
	cmd.Flags().StringVar(&pbPath, "path", pbPath, "proto文件地址,支持传入目录")
	return cmd
}

func addAPICommand() *cobra.Command {
	pbPath, _ := os.Getwd()
	var routerGroup = ""
	var routerName = ""
	var routerMethod = "POST"
	cmd := &cobra.Command{
		Use:   "addapi",
		Short: "给路由组新增一个api",
		Long:  "仅适用于Register方式注入路由",
		Run: func(cmd *cobra.Command, args []string) {
			if routerName == "" {
				_, _ = fmt.Fprintf(os.Stderr, "路由名称 --name 不能为空")
				return
			}
			routerName = toolkit.FirstUpper(routerName)
			err := proto.AddAPI(pbPath, routerGroup, routerName, routerMethod)
			if err != nil {
				_, _ = fmt.Fprint(os.Stderr, err)
				os.Exit(1)
			}
		},
	}
	cmd.Flags().StringVar(&pbPath, "path", pbPath, "proto单个文件地址")
	cmd.Flags().StringVar(&routerName, "name", routerName, "该路由名称")
	cmd.Flags().StringVar(&routerGroup, "svc", routerGroup, "需要注入的路由组名称")
	cmd.Flags().StringVar(&routerMethod, "method", routerMethod, "请求方式POST/GET...")
	return cmd
}

func addRPCCommand() *cobra.Command {
	pbPath, _ := os.Getwd()
	var svcName = ""
	var rpcName = ""
	cmd := &cobra.Command{
		Use:   "addrpc",
		Short: "给service新增一个rpc",
		Long:  "给service新增一个rpc",
		Run: func(cmd *cobra.Command, args []string) {
			err := proto.AddRPC(pbPath, svcName, rpcName)
			if err != nil {
				_, _ = fmt.Fprint(os.Stderr, err)
				os.Exit(1)
			}
		},
	}
	cmd.Flags().StringVar(&pbPath, "path", pbPath, "proto单个文件地址")
	cmd.Flags().StringVar(&rpcName, "name", rpcName, "该RPC名称")
	cmd.Flags().StringVar(&svcName, "svc", svcName, "需要注入到哪个service中")
	return cmd
}

func outputMdCommand() *cobra.Command {
	pbPath, _ := os.Getwd()
	var svcName = ""
	var rpcName = ""
	var include []string
	cmd := &cobra.Command{
		Use:   "md",
		Short: "给路由组的api输出markdown文档",
		Long:  "给路由组的api输出markdown文档",
		Run: func(cmd *cobra.Command, args []string) {
			err := proto.OutputMD(pbPath, svcName, rpcName, include)
			if err != nil {
				_, _ = fmt.Fprint(os.Stderr, err)
				os.Exit(1)
			}
		},
	}
	cmd.Flags().StringVar(&pbPath, "path", pbPath, "proto单个文件地址")
	cmd.Flags().StringVar(&rpcName, "name", rpcName, "路由/RPC的名称")
	cmd.Flags().StringVar(&svcName, "svc", svcName, "路由/RPC在哪个service中")
	cmd.Flags().StringSliceVar(&include, "include", include, "路由/RPC依赖到的其他proto文件列表,用于字段注释补全(不支持目录)")
	return cmd
}

func addRouteCommand() *cobra.Command {
	var pbPath = ""
	var svcName = ""
	var genTo = ""
	var apiPath = ""
	cmd := &cobra.Command{
		Use:   "addroute",
		Short: "快速添加一个路由组",
		Long:  "快速添加一个路由组",
		Run: func(cmd *cobra.Command, args []string) {
			// windows 兼容 用这几个盘符足够了吧
			if toolkit.GetGOOS() == toolkit.Windows {
				if strings.HasPrefix(apiPath, "C:") || strings.HasPrefix(apiPath, "D:") ||
					strings.HasPrefix(apiPath, "E:") || strings.HasPrefix(apiPath, "F:") ||
					strings.HasPrefix(apiPath, "G:") || strings.HasPrefix(apiPath, "H:") {
					_, _ = fmt.Fprintf(os.Stderr, "windows模式下 --api 参数不要以 / 开头, 程序将自动帮你补全\n")
					return
				}
				if apiPath != "" {
					apiPath = fmt.Sprintf("/%s", apiPath)
				}
			}
			if svcName == "" {
				_, _ = fmt.Fprintf(os.Stderr, "路由组的名称 -- name 不能为空\n")
				return
			}
			cname := toolkit.Calm2Case(svcName)

			if pbPath == "" {
				pbPath, _ = os.Getwd()
				_tempDir := pbPath
				if toolkit.GetGOOS() == toolkit.Windows {
					pbPath = fmt.Sprintf("%s\\%s.proto", pbPath, cname)
				} else {
					pbPath = fmt.Sprintf("%s/%s.proto", pbPath, cname)
				}
				_, _ = fmt.Fprintf(os.Stdout, "填写proto生成路径为空,将生成至缺省路径: %+v\n", pbPath)
				// 创建文件
				_, err := os.Stat(pbPath)
				// 需要创建文件 填充内容
				if err != nil {
					if !os.IsNotExist(err) {
						_, _ = fmt.Fprintf(os.Stderr, "检索文件失败: %+v\n", err)
						return
					}
					pkgName := filepath.Base(_tempDir)
					pkgName = strings.ReplaceAll(pkgName, "-", "_") // 替换- 防止不识别包
					pkgName = toolkit.Calm2Case(pkgName)
					content := fmt.Sprintf("syntax = \"proto3\";\npackage %s;\n", pkgName)
					err := ioutil.WriteFile(pbPath, []byte(content), fs.ModePerm)
					if err != nil {
						_, _ = fmt.Fprintf(os.Stderr, "写入%s文件失败: %+v\n", pbPath, err)
						return
					}
				}
			}
			if genTo == "" {
				genTo = fmt.Sprintf("./internal/controller/%s_controller.go", cname)
			}
			if apiPath == "" {
				apiPath = fmt.Sprintf("/api/%s", cname)
			}

			if err := proto.AddRoute(pbPath, svcName, apiPath, genTo); err != nil {
				_, _ = fmt.Fprintf(os.Stderr, "add route err: %+v\n", err)
				return
			}
		},
	}
	cmd.Flags().StringVar(&pbPath, "path", pbPath, "要将该路由组生成到哪个proto文件中,填写文件地址")
	cmd.Flags().StringVar(&svcName, "name", svcName, "生成的router路由组的名称,一般为模块名,如User")
	cmd.Flags().StringVar(&genTo, "gento", genTo, "该路由组具体路由的实现方法将被生成到的位置,默认生成到./internal/controller/module_name_controller.go文件下")
	cmd.Flags().StringVar(&apiPath, "api", apiPath, "供访问的路由组api前缀,如: /api/user/info 组路由api前缀为 /api/user")

	return cmd
}

func addSvcCommand() *cobra.Command {
	var pbPath = ""
	var svcName = ""
	var genTo = ""
	var apiPath = ""
	cmd := &cobra.Command{
		Use:   "addsvc",
		Short: "快速添加一个rpc服务",
		Long:  "快速添加一个rpc服务",
		Run: func(cmd *cobra.Command, args []string) {
			// windows 兼容 用这几个盘符足够了吧
			if toolkit.GetGOOS() == toolkit.Windows {
				if strings.HasPrefix(apiPath, "C:") || strings.HasPrefix(apiPath, "D:") ||
					strings.HasPrefix(apiPath, "E:") || strings.HasPrefix(apiPath, "F:") ||
					strings.HasPrefix(apiPath, "G:") || strings.HasPrefix(apiPath, "H:") {
					_, _ = fmt.Fprintf(os.Stderr, "windows模式下 --api 参数不要以 / 开头, 程序将自动帮你补全\n")
					return
				}
				if apiPath != "" {
					apiPath = fmt.Sprintf("/%s", apiPath)
				}
			}
			if svcName == "" {
				_, _ = fmt.Fprintf(os.Stderr, "路由组的名称 -- name 不能为空\n")
				return
			}
			cname := toolkit.Calm2Case(svcName)

			if pbPath == "" {
				pbPath, _ = os.Getwd()
				_tempDir := pbPath
				if toolkit.GetGOOS() == toolkit.Windows {
					pbPath = fmt.Sprintf("%s\\%s.proto", pbPath, cname)
				} else {
					pbPath = fmt.Sprintf("%s/%s.proto", pbPath, cname)
				}
				_, _ = fmt.Fprintf(os.Stdout, "填写proto生成路径为空,将生成至缺省路径: %+v\n", pbPath)
				// 创建文件
				_, err := os.Stat(pbPath)
				// 需要创建文件 填充内容
				if err != nil {
					if !os.IsNotExist(err) {
						_, _ = fmt.Fprintf(os.Stderr, "检索文件失败: %+v\n", err)
						return
					}
					pkgName := filepath.Base(_tempDir)
					pkgName = strings.ReplaceAll(pkgName, "-", "_") // 替换- 防止不识别包
					pkgName = toolkit.Calm2Case(pkgName)
					content := fmt.Sprintf("syntax = \"proto3\";\npackage %s;\n", pkgName)
					err := ioutil.WriteFile(pbPath, []byte(content), fs.ModePerm)
					if err != nil {
						_, _ = fmt.Fprintf(os.Stderr, "写入%s文件失败: %+v\n", pbPath, err)
						return
					}
				}
			}
			if genTo == "" {
				genTo = fmt.Sprintf("./internal/services/%s_service.go", cname)
			}
			if apiPath == "" {
				apiPath = fmt.Sprintf("/api/%s", cname)
			}

			if err := proto.AddRoute(pbPath, svcName, apiPath, genTo); err != nil {
				_, _ = fmt.Fprintf(os.Stderr, "add route err: %+v\n", err)
				return
			}
		},
	}
	cmd.Flags().StringVar(&pbPath, "path", pbPath, "要将该路由组生成到哪个proto文件中,填写文件地址")
	cmd.Flags().StringVar(&svcName, "name", svcName, "生成的服务名称,一般为模块名,如User")
	cmd.Flags().StringVar(&genTo, "gento", genTo, "该服务的实现方法将被生成到的位置,默认生成到./internal/services/module_name_service.go文件下")

	return cmd
}
